C.S.M.P. Digest Mon, 13 Jul 92 Volume 1 : Issue 140 Today's Topics: Non-optimized Compiler. Was RE: is System 7 written in c++ Socket Interface on MacTCP How to allocate global for CDEVs? Problems with putting a string into a list MIDI routines Multiple "System Beeps" possible? ZREF error? PS font name, How to get it from FOND?! The Comp.Sys.Mac.Programmer Digest is moderated by Michael A. Kelly. The digest is a collection of article threads from the internet newsgroup comp.sys.mac.programmer. It is designed for people who read c.s.m.p. semi- regularly and want an archive of the discussions. If you don't know what a newsgroup is, you probably don't have access to it. Ask your systems administrator(s) for details. (This means you can't post questions to the digest.) Each issue of the digest contains one or more sets of articles (called threads), with each set corresponding to a 'discussion' of a particular subject. The articles are not edited; all articles included in this digest are in their original posted form (as received by our news server at cs.uoregon.edu). Article threads are not added to the digest until the last article added to the thread is at least one month old (this is to ensure that the thread is dead before adding it to the digest). Article threads that consist of only one message are generally not included in the digest. The entire digest is available for anonymous ftp from ftp.cs.uoregon.edu [128.223.8.8] in the directory /pub/mac/csmp-digest. The most recent issues are available from sumex-aim.stanford.edu [36.44.0.6] in the directory /info-mac/digest/csmp. If you don't have ftp capability, the sumex archive has a mail server; send a message with the text '$MACarch help' (no quotes) to LISTSERV@ricevm1.rice.edu for more information. These digest is also available via email. Just send a note saying that you want to be on the digest mailing list to mkelly@cs.uoregon.edu, and you will automatically receive each new issue as it is created. Sorry, back issues are not available through the mailing list. Send administrative mail to mkelly@cs.uoregon.edu. ------------------------------------------------------- From: haceaton@aplcomm.jhuapl.edu (Harry Eaton) Subject: Non-optimized Compiler. Was RE: is System 7 written in c++ Organization: The Johns Hopkins University Applied Physics Laboratory Date: Mon, 8 Jun 92 14:33:50 GMT In article <935@6sceng.UUCP> blm@6sceng.UUCP (Brian Matthews) writes: >... I would say that the System 7 Finder, from >an assembly point of view, is some of the worst code I've ever seen. I >don't know if it's an inherent limitation in C++ or Apple is using a >horrible compiler, but if you trace through the Finder for a bit, it's >obvious why the System 7 Finder is so ploddingly slow. This is quite true. A particularly bad example of code taken from the system 7 OS (not the finder) follows (note: labels, names etc. are made up to protect the code's identity :-). The comments are mine): sub Link.w a6,#$0000 ; this compiler links *all* subroutines move.l d7,-(a7) ; save this register for useless workspace move.l a5,d0 ; save the a5 register in d0 movea.l (lowglobal),a5 ; load it with a new value move.l d0,d7 ; oops - should have used d7 earlier tst.w theVar(a5) ble.s @1 move.w theVar(a5),d0 ; better put this in a register subq.w #1,theVar(a5) ; oops no register needed @1 move.l d7,d0 ; ok - lets go the long way home movea.l d0,a5 ; back the way we came! move.l $fffc(a6),d7 ; pop d7 off the stack unlk a6 ; unlink and return rts The compiler is clearly far from optimized. The link instruction is totally unnecessary for this particular routine; there are no local variables, and no stack passed arguments. Saving D7 on the stack is unnecessary because D7's use is unnecessary. Saving a5 in d0 would be good except that the compiler changes its mind right away, and decides to use d7 instead. The variable that will be manipulated is needlessly loaded into the d0 register, and then manipulated directly in memory. When the old a5 contents are restored the value follows the quite schizophrenic path from d7 to d0 to a5. Finally, when d7 is popped from the stack, it is pulled from an offset relative to the link. This has the advantage that the stack can have an indeterminate number of things left on it and the disadvantage that its slower and takes more bytes. In this case, the stack is never indeterminate so the normal move.l (a7)+,d7 could be used. Some of the above arguments would be false if the routine were ever entered from locations other than the top, or if the value of d0 on exit is important. ease of maintenance and portability. Presumably the time to market forces and competition in software are similar to those in the hardware arena. Somehow the software giants make more $'s than the hardware giants do despite the fact that much software today is satisfactory only because of the great leaps in hardware performance. To end on a good note, the mac ROM code looks pretty decent and fortunately its still heavily used. Thanks for reading my diatribe harry eaton haceaton@aplcomm.jhuapl.edu +++++++++++++++++++++++++++ From: neeri@iis.ethz.ch (Matthias Neeracher) Date: 9 Jun 92 12:50:01 GMT Organization: Integrated Systems Laboratory, ETH, Zurich In article <1992Jun8.143350.3311@aplcen.apl.jhu.edu> haceaton@aplcomm.jhuapl.edu (Harry Eaton) writes: >In article <935@6sceng.UUCP> blm@6sceng.UUCP (Brian Matthews) writes: >>... I would say that the System 7 Finder, from >>an assembly point of view, is some of the worst code I've ever seen. > >This is quite true. A particularly bad example of code taken from the >system 7 OS (not the finder) follows > move.w theVar(a5),d0 ; better put this in a register > subq.w #1,theVar(a5) ; oops no register needed >@1 move.l d7,d0 ; ok - lets go the long way home This is an annoying habit of apples C compiler: If you write x--; the above code will result, as opposed to if you write - --x; >To end on a good note, the mac ROM code looks pretty decent and fortunately >its still heavily used. Yes, and this pretty much invalidates the complaints that the performance problems of Finder et al. are due to sloppy code generation. Wasn't there a discussion here a while ago that most programs spend the majority of their time in toolbox calls ? Matthias - ----- Matthias Neeracher neeri@iis.ethz.ch `We say "gestalt" when things combine to act in ways we can't explain' -- Marvin Minsky, _The Society Of Mind_ +++++++++++++++++++++++++++ From: mxmora@unix.SRI.COM (Matt Mora) Date: 10 Jun 92 02:02:14 GMT Organization: SRI International, Menlo Park, California In article neeri@iis.ethz.ch (Matthias Neeracher) writes: >Yes, and this pretty much invalidates the complaints that the performance >problems of Finder et al. are due to sloppy code generation. Wasn't there a >discussion here a while ago that most programs spend the majority of their >time in toolbox calls ? The people at Apple that are creating the RISC mac's said at the WWDC that they found most application spend about 80% or more of their time in the toolbox. And of the toolbox calls used Drawtext was the most used and moveto was the runner up. They needed to know which routines to optimize for RISC that would gain the most benefit. So if they optimized the critical calls, all applications would see a big improvement in performance on a RISC machine without any modifications. Matt - -- ___________________________________________________________ Matthew Mora | my Mac Matt_Mora@sri.com SRI International | my unix mxmora@unix.sri.com ___________________________________________________________ --------------------------- From: ldh@svl.cdc.com (Lawrence Hare) Subject: Socket Interface on MacTCP Date: 8 Jun 92 17:25:05 GMT Organization: Control Data Corporation, Silicon Valley Operations I am attempting to locate a socket interface library compliant with BSD 4.3 for use with MacTCP. This will permit crossplatform code at the network level (Mac & PC). NOVELL used to have one but it is no longer on the market. I am told that there are some public domain offerings available - but I know not where. If anyone can tell me where I may obtain such a library, I would be very grateful. +++++++++++++++++++++++++++ From: hardin@dino.cad.mcc.com (John Hardin) Date: 9 Jun 92 23:55:03 GMT Organization: MCC CAD Program, Austin, Texas Lawrence Hare (ldh@svl.cdc.com) writes: > > I am attempting to locate a socket interface library compliant with > BSD 4.3 for use with MacTCP. This will permit crossplatform code > at the network level (Mac & PC). NOVELL used to have one but it > is no longer on the market. I am told that there are some public > domain offerings available - but I know not where. > > If anyone can tell me where I may obtain such a library, I would > be very grateful. The folks at MIT have written this VERY thing! (However, I can't vouch for it's BSD 4.3 compliance, though.) I ftp'd it from net-dist.mit.edu (18.72.0.3). If I remember correctly, it's part of the TechMail-2.0 release. It was originally written for MPW (3.1?) and MacTCP 1.0, but I have subsequently ported it to ThinkC 4.0/5.0 (running on MacTCP 1.1). I've also fixed some bugs. I haven't finished ALL of my testing, but as soon as I do, I'll return the code to MIT (given they want it). - -jwh - -- John W. Hardin phone: (512)338-3535 MCC email: hardin@mcc.com 3500 W. Balcones Center Dr fax: (512)338-3897 Austin, TX 78759-6509 uucp: ...!cs.utexas.edu!milano!cadillac!hardin --------------------------- From: mmoss@engws5.ic.sunysb.edu (Matthew D Moss) Subject: How to allocate global for CDEVs? Organization: State University of New York at Stony Brook Date: Mon, 8 Jun 1992 18:35:43 GMT I am writing a Control Panel Device using the method described in THINK C 4.0's class library. I need to use modal dialogs, however, the standard calls to read the dialog from the resource and enter the modal dialog don't do anything. As I guess, this is due to the fact that CDEV's cannot have global variables. How can I get around this? (I don't have IM). Thanx in advance. - -- - ------------------------------------------------------------------------------- Matthew David Moss mmoss@ic.sunysb.edu "Artificial intelligence is no mmoss@ccmail.sunysb.edu match for natural stupidity." +++++++++++++++++++++++++++ From: keith@taligent.com (Keith Rollin) Date: 9 Jun 92 18:11:32 GMT Organization: Taligent In article <1992Jun8.183543.1098@sbcs.sunysb.edu>, mmoss@engws5.ic.sunysb.edu (Matthew D Moss) writes: > > > I am writing a Control Panel Device using the method described in THINK C > 4.0's class library. I need to use modal dialogs, however, the standard > calls to read the dialog from the resource and enter the modal dialog > don't do anything. > > As I guess, this is due to the fact that CDEV's cannot have global variables. > How can I get around this? (I don't have IM). I'm afraid your guess is incorrect. The problem is not due to CDEV's not being able to use global variables. The Dialog Manager routines don't depend on the existence or non-existence of an application's globals (other than a valid A5 world with QD globals, which any CDEV will have). (BTW: CDEV's _can_ use global variables. THINK users can use the A4 routines, and MPW users can use the technique in Technote #256.) Your problem probably lies elsewhere, like in the formation of your DLOG or DITL. It's possible, for example, that your dialog is being created at a location way off your screen, or that its size is 0, 0. I've never experienced your problem, so without more details, I couldn't suggest any more reasons for the problem. - -- Keith Rollin Phantom Programmer Taligent, Inc. --------------------------- From: marshall@kauri.vuw.ac.nz (Stephen Marshall) Subject: Problems with putting a string into a list Date: 8 Jun 92 23:33:30 GMT Organization: Victoria University of Wellington Hi, I'm having trouble feeding a string into a list cell, the string looks fine when I check it with lightsbug, but when it is displayed on the list, it gets cut off at the end, and uaually gets an extra character (square box) at front, increasing the length of the data put into the list by one gets the end right, but why should that be necessary, and why does the other rubbish end up in front? Any help apprecieated, Stephen (code follows:) temp := LAddRow(1, (counter - 1), theListHandle); SetPt(cSize, 0, (counter - 1)); {extract the data from the ProcessInfoRec} theError := GetProcessInformation(myPSNList.element[counter], theProcessInfo); theString := theProcessInfo.processName^; {Insert the data into the list} LSetCell(@theString, (Length(theString) + 1), cSize, theListHandle); Thanks again, Stephen +++++++++++++++++++++++++++ From: mxmora@unix.SRI.COM (Matt Mora) Date: 10 Jun 92 01:50:38 GMT Organization: SRI International, Menlo Park, California In article <1992Jun8.233330.7161@rata.vuw.ac.nz> marshall@kauri.vuw.ac.nz (Stephen Marshall) writes: The problem is that you are storing the length byte with the data. If you write your own LDEF you can deal with it yourself otherwise you need to strip it out before you insert it in to the list and put it back when you get the data out. (if you do) Try: >{Insert the data into the list} > LSetCell(@theString, (Length(theString) + 1), cSize, theListHandle); LSetCell(Ptr(Ord(@theString)+1),Length(thestring),cSize, theListHandle); Now when you want the string back: datalen:=255; LGetCell(Ptr(Ord(@theString)+1),datalen,theCell,theListHandle); theString[0]:=chr(datalen); { compiler might complain about array bounds} Matt - -- ___________________________________________________________ Matthew Mora | my Mac Matt_Mora@sri.com SRI International | my unix mxmora@unix.sri.com ___________________________________________________________ --------------------------- Organization: Junior, Math/Computer Science, Carnegie Mellon, Pittsburgh, PA Date: Tue, 9 Jun 1992 12:16:30 -0400 From: Lian-Keng Lim Subject: MIDI routines Hello, I am looking for some MIDI routines for an application that I am writing in Think C. Can anyone point me in the right direction as to where I can source these codes? I would also appreciate the following information if anyone can supply them... 1. what is opcode MIDI intrepeter? if it means anything at all... 2. are there C codes for MIDIPascal routines by AlTech Systems? If so, how can I get them. 3.where and how can I get a copy of Mac Software Catalog? Thanks a bunch in advance for all information. Peace, Keng. +++++++++++++++++++++++++++ From: steve@oceania.com (Steve Dakin) Date: 9 Jun 92 20:04:53 GMT Organization: Oceania Health Care Systems In article <8eBBZS200iUyA2zHMW@andrew.cmu.edu> writes: > 2. are there C codes for MIDIPascal routines by AlTech Systems? If so, > how can I get them. According to Altech's product information, the MidiPascal routines require "Lightspeed Pascal, Lightspeed C, or TurboPacal." Also, the girl I spoke with at Altech said they are compatible with THINK C 5.0. You might also want to try Apple's MIDI Management Tools Set. I used this in a MIDI program I wrote and it worked quite well. It's less expensive (that's a first) at $35 vs. $100 for Altech's routines. However, if you plan to sell or distribute anything you write, Apple requires a $100 licensing fee per product per year and Altech's is free of licensing fees. Altech's number is 318-868-8036 APDA's number is 800-282-2732 Don't expect to receive any technical information from either number. - -Steve - -- Steve Dakin Oceania Health Care Systems steve@oceania.com (NeXT mail) Palo Alto, CA (415) 322-0127 jester@oceania.com "That one deserves a ... WOW!" --------------------------- From: dvb@squid.inmet (David V. Baker) Subject: Multiple "System Beeps" possible? Date: 9 Jun 92 17:01:58 GMT Organization: Intermetrics, Inc. (Ada Division) *I'm looking to have different beeps for different applications.* Does anyone "out there" know if (and how) I can have multiple "beeps" on my machine? Specifically, I would like MacX (and therefore my terminal windows) to have a different beep-sound than the rest of my machine. Is there some magic id number I could paste a sound into MacX and bypass the request to the System for the standard beep? Could an INIT of some sort force an override of the beep sound? I don't mind hacking up a copy of MacX (or any other application), if I know where to look. If you can answer, thanks for the smarts. dvb - -- - ------------------------------------------------------------------- David V. Baker Intermetrics, Inc. dvb@inmet.camb.inmet.com Cambridge, MA 02138 (617) 661-1840x4644 +++++++++++++++++++++++++++ From: aconn@jade.tufts.edu (Zoom Master 1 ) Date: 9 Jun 92 19:03:16 GMT Organization: Tufts University - Medford, MA Use the GREAT shareware program Speed Beep. Get version 2.0.6. +++++++++++++++++++++++++++ From: barrett@ial4.jsc.nasa.gov (Jim Barrett) Date: 9 Jun 92 20:31:52 GMT Organization: Lockheed Engineering & Sciences Co. In article , dvb@squid.inmet (David V. Baker) writes: > *I'm looking to have different beeps for different applications.* > > Does anyone "out there" know if (and how) I can have multiple "beeps" > on my machine? Specifically, I would like MacX (and therefore my > terminal windows) to have a different beep-sound than the rest of my > machine. Is there some magic id number I could paste a sound into MacX > and bypass the request to the System for the standard beep? Could an > INIT of some sort force an override of the beep sound? I don't know of an INIT, but I know how to do this with ResEdit. WARNING - the following is more that I know about the Macintosh. I learned this trick from a Mac developer friend. Apparently, when the system opens any resource, it searches the current application, and then it searches the system. If you had selected SND id 256, for instance, and your software generates a beep, the system searches your open application for sound resource id 256, and then it searches the system itself, which is where it typically finds the sound. However, if you set your system beep to whatever sound is associated with, say, 256, and there just happens to be a sound id 256 in your current application, the one in your application will sound when your app ic current, and the one in the system suitcase will sound for other apps. What I've done: I resedited my system suitcase (make a backup first, ok?), and created a sound resource of ID 256, and gave it a name like "sound #256". Then I open the sound control panel and make "sound #256" the system beep. Finally, I resedit my application (make another backup first, ok?), and copy in a sound resource, and give it a resource id of 256. voila! My telnet application has a nice short beep, and my other applications have a longer, more entertaining beep. If anyone has a better idea, I'm sure they'll post ... :-) Regards, Jim --------------------------- From: jstevens@crick.ssctr.bcm.tmc.edu (Jason Philip Stevens) Subject: ZREF error? Date: 9 Jun 92 22:31:50 GMT Organization: Baylor College of Medicine, Houston, Tx I'm writing an application with TCL 1.1 and Think C 5.0. I keep getting "ZREF" errors that ask me to remove objects and re-make my code. This is a painfully time-consuming process; does anyone have any idea what causes these errors and what I can do to prevent them? - -jps PS: Frequent = ~3 times/day, code size is about 106,000 lines, on a mac II with sys 7.0 (no tuneup) and 5 mb ram. - -- Jason Stevens Internet: jstevens@bcm.tmc.edu Network User Services Voice: (713) 798-7370 Baylor College of Medicine Opinions expressed are mine alone. +++++++++++++++++++++++++++ From: mspace@netcom.com (Brian Hall) Date: Tue, 09 Jun 92 23:32:52 GMT Organization: Netcom - Online Communication Services (408 241-9760 guest) jstevens@crick.ssctr.bcm.tmc.edu (Jason Philip Stevens) writes: >I'm writing an application with TCL 1.1 and Think C 5.0. I keep getting "ZREF" errors that ask me to remove objects and re-make my code. This is a painfully >time-consuming process; does anyone have any idea what causes these errors and >what I can do to prevent them? >-jps >PS: Frequent = ~3 times/day, code size is about 106,000 lines, on a mac II with >sys 7.0 (no tuneup) and 5 mb ram. I had the same problem working on a IIfx 20/210. My project contained about 40 subprojects and around 200 source files. Even though ThC claims to use multifinder temp mem, meaning you should not have to increase the partition size, I found the only way to reliably exorcise the ZREF error was to increase the compilers partition by a large amount (I made it 4M for that particular app, and 2M for a smaller app I am doing on a IIsi). My other beef with 5.0 is that it *still* uses the resource manager for the project file. This can get *real* slow with a large project. Just the time it takes to remove and then add resources during a compile can become significant. A little trick I use is to do a remove objects if a significant number of files will need to be recompiled. This is faster because you are just doing address instead of a bunch of changedres calls. - -- \ | / | Brian Hall mspace@netcom.com - : - | Mark/Space Softworks Applelink: markspace /|\ | America Online: MarkSpace |-+-| | /-\|/-\ | People don't kill people, toasters kill people. --------------------------- From: de19@umail.umd.edu (Dana S Emery) Subject: PS font name, How to get it from FOND?! Date: 10 Jun 92 06:59:59 GMT Organization: Personal In article <13798@umd5.umd.edu>, de19@umail.umd.edu (Dana S Emery) writes: > > In article <14271@ucdavis.ucdavis.edu>, lim@iris.ucdavis.edu (Lloyd Lim) writes: > > > > In article <10s9ocINNdd2@agate.berkeley.edu> ewylie@ocf.berkeley.edu (Elizabeth Wylie) writes: > > > > > >I am trying to determine whether a particular font (given a font name and > > >number) has a PostScript counterpart that will be handled by ATM. I've > > >been told that ATM has some callback routines that would help me out, > > >but I don't know what these routines are. > > > > > > Yes, the procedure is named fontAvailableATM. It's not hard but it's > > a bit long to describe here. > > Suitcase is able to access some field in the FOND which defines the > PS font name (ie TimesRomBol), so ATM shouldnt be necesary (unless one > also needed to confirm the existance of the related 'LWFN'). I vaguely > remember some doc on this, but cant place it just now. > > DSE (de19@umail.umd.edu) in <1992Jun9.184919.22275@reed.edu>, orpheus@reed.edu (P. Hawthorne) went on at length re: ATM backdoor solution, which is ok, but leaves my (de19) question unanswered. - Suitcase gets the PS file name from inspection of the FOND/FONT/NFNT/.. - what is it looking at? My question is more than idle, as I have dreams of writing a font editor some day. Dana S Emery (de19@umail.umd.edu) +++++++++++++++++++++++++++ From: orpheus@reed.edu (P. Hawthorne) Date: 11 Jun 92 00:50:56 GMT Organization: Reed College, Portland, Oregon ewylie@ocf.berkeley.edu (Elizabeth Wylie) inquires: . I am trying to determine whether a particular font (given a font name and . number) has a PostScript counterpart that will be handled by ATM. I've been . told that ATM has some callback routines that would help me out, but I . don't know what these routines are. orpheus@reed.edu (Prometheus Hawthorne) replies: . The package is available for anonymous ftp on sumex-aim.stanford.edu. . Adobe assumes you are using Think C and they have been unable to come . up with a backdoor interface for other compilers. Just in case, here is my . code for using ATM with Think Pascal. [Meanwhile, on another typographical tangent...] de19@umail.umd.edu (Dana S Emery) writes: . Suitcase is able to access some field in the FOND which defines the . PS font name (ie TimesRomBol), so ATM shouldnt be necesary (unless one . also needed to confirm the existance of the related 'LWFN'). I vaguely . remember some doc on this, but cant place it just now. orpheus@reed.edu (P. Hawthorne) defers: . The best documentation for this (as well as the most lucid, descriptive and . salient discussion of the FOND resource) is available from Adobe Developer . Technical Support. de19@umail.umd.edu (Dana S Emery) writes: . - Suitcase gets the PS file name from inspection of the FOND/FONT/NFNT/ . - What is it looking at? I am hoping not to have to explain the FOND mechanism itself, since it is an involved exercise in parsing and sorting that is best described by the Adobe documentation. That being said, at least post my source code for doing it, and I can give you an overview of what is involved. In QuickDraw, a typeface is available to you by number, and resource name. Neither system is any good for typographical purposes. Look at Adobe Illustrator for an example of good font picking. The PostScript names are superior. If you step through every typeface by QuickDraw resource number, just like TextFont, you can get the base PostScript typeface name. Maybe just for thrills you would use a heap for this with a priority function on the resource name. If you step through every style by QuickDraw style index, just like TextFace, you can get a bunch of suffixes to attach to your base font name. Then you have a mapping between what PostScript type face and style you want to use and what QuickDraw numbers you have to use in order to generate that face and style on the Macintosh screen. As for the arcane nitty gritty, mostly offsets from indices into offsets from the resource handle, this is what the FOND documentation from Adobe is for. Using it, I was able to replace that agonizingly long typeface menu with a series of menus for type family, face and style. There are some intricacies involved, but if you can parse out the Futura family youUre doing fine. (Oh yeah, watch out for Futura Condensed.) Here is as far as I got with doing this trick, right after getting Think Pascal and working my way through the toolbox. No fair criticizing the style, cuz I was just barely getting used to using Pascal instead of C and was just reverse engineering the whole thing before I got the documentation. I think there's a bug in the QuickSort. Apologies made, here it is. Theus (orpheus@reed.edu) "Man, these self-inflicted caffeine deprivation headaches suck..." - ---------- Cut here Type FondRecord = Record FlagWord: Integer; FamilyID: Integer; FirstChar: Integer; LastChar: Integer; Ascent: Integer; Descent: Integer; Leading: Integer; WidMax: Integer; WidOff: Longint; KernOff: Longint; StyleMapOff: Longint; End; StyleMappingTable = Record FontClass: Integer; EncodeOff, Reserved: Longint; StyleIndex: Packed Array[0..47] Of Byte; NumStyles: Integer; BaseFont: Str255; End; FontRecord = Record PSFamily: String[64]; PSFace: String[64]; PSStyle: String[64]; QDFont: String[64]; QDFace: Integer; QDStyle: Style; End; FontSpec = Record QDFace: Integer; QDStyle: Style; QDSize: Integer; End; Typographer = Object(Abstract) Count: Integer; Fonds: Integer; Fonts: Array[0..maxFonts] Of FontRecord; Procedure Typographer.Construct; Procedure Typographer.Destruct; Procedure Typographer.Update; Procedure Typographer.Expect (aLongint: Longint); Procedure Typographer.Insert (aFont: FontRecord); Function Typographer.GetEntry (anIndex: Integer): FontRecord; Procedure Typographer.SetEntry (anIndex: Integer; aFont: FontRecord); Procedure Typographer.SetMenu (aMenu: MenuHandle; aContents: Integer; aFamily, aFace: Str255); Function Typographer.GetDefaultFace (aPSFamily: Str255): Str255; Function Typographer.GetDefaultStyle (aPSFamily, aPSFace: Str255): Str255; Function Typographer.GetFontSpec (aPSFamily, aPSFace, aPSStyle: Str255; aSize: Extended): FontSpec; Procedure Typographer.Develop; Procedure Typographer.Sort; Procedure Typographer.Unique; Procedure Typographer.Harmony; End; Const fontRecordSize = Longint(SizeOf(FontRecord)); Var theTypographer: Typographer; Procedure Typographer.Construct; Begin Lock; Count := -1; Fonds := 0; End; Procedure Typographer.Update; Begin If CountResources('FOND') <> Fonds Then Begin Count := 0; Develop; End; End; Procedure Typographer.Expect (aLongint: Longint); Begin aLongint := 6 + (aLongint + 1) * fontRecordSize; Ignore(Grow(aLongint)); End; Procedure Typographer.Insert (aFont: FontRecord); Var aPtr: Ptr; Begin Expect(Count + 3); Count := Count + 1; SetEntry(Count, aFont); End; Function Typographer.GetEntry (anIndex: Integer): FontRecord; Var aPtr: Ptr; aFont: FontRecord; Begin aPtr := Ptr(Longint(@Fonts) + fontRecordSize * anIndex); BlockMove(aPtr, @aFont, fontRecordSize); GetEntry := aFont; End; Procedure Typographer.SetEntry (anIndex: Integer; aFont: FontRecord); Var a, i, o: Ptr; e, u: Longint; aPtr: Ptr; Begin aPtr := Ptr(Longint(@Fonts) + fontRecordSize * anIndex); a := @Self; e := HandleSize(Self); i := Ptr(Longint(a) + Longint(e)); o := @Fonts; u := fontRecordSize * anIndex; If (Longint(aPtr) < Longint(o)) Then Danger('The typeface Typographer attempted to thrash low memory.') Else If (Longint(aPtr) > Longint(e)) Then Danger('The typeface Typographer attempted to thrash high memory.'); BlockMove(@aFont, aPtr, fontRecordSize); End; Function Typographer.GetFontSpec (aPSFamily, aPSFace, aPSStyle: Str255; aSize: Extended): FontSpec; Var a, e: Integer; aFont: FontRecord; found: Boolean; Begin GetFontSpec.QDFace := 0; GetFontSpec.QDStyle := []; GetFontSpec.QDSize := Trunc(aSize); found := false; For a := 0 To Count Do Begin aFont := GetEntry(a); If (aFont.PSFamily = aPSFamily) And (aFont.PSFace = aPSFace) And (aFont.PSStyle = aPSStyle) Then Begin found := true; GetFontSpec.QDFace := aFont.QDFace; GetFontSpec.QDStyle := aFont.QDStyle; a := Count; End; End; If Not found Then Notice('Could not get a font specification with PostScript identifiers.'); End; Function Typographer.GetDefaultFace (aPSFamily: Str255): Str255; Var a, e: Integer; aFont: FontRecord; found, gotten: Boolean; Begin found := false; GetDefaultFace := 'Regular'; For a := 0 To Count Do Begin aFont := GetEntry(a); If (aFont.PSFamily = aPSFamily) Then If (aFont.QDStyle = []) Then Begin If (aFont.PSFace = 'Regular') Or (aFont.PSFace = 'Medium') Then Begin found := true; GetDefaultFace := aFont.PSFace; End; End Else If found Then a := Count End; End; Function Typographer.GetDefaultStyle (aPSFamily, aPSFace: Str255): Str255; Var a, e: Integer; aFont: FontRecord; found, gotten: Boolean; Begin found := false; gotten := false; GetDefaultStyle := 'Regular'; For a := 0 To Count Do Begin aFont := GetEntry(a); If (aFont.PSFamily = aPSFamily) And (aFont.PSFace = aPSFace) Then Begin found := true; If (aFont.QDStyle = []) Then If Not gotten Then Begin Begin GetDefaultStyle := aFont.PSStyle; gotten := true; End; End Else If (aFont.PSStyle = 'Roman') Or (aFont.PSStyle = 'Regular') Or (aFont.PSStyle = 'Book') Or (aFont.PSStyle = 'Medium') Then Begin GetDefaultStyle := aFont.PSStyle; End; End Else If gotten Then a := Count Else If found Then Begin Caution('Problem finding default style.'); a := Count; End; End; End; Procedure Typographer.SetMenu (aMenu: MenuHandle; aContents: Integer; aFamily, aFace: Str255); Var a, e, i: Integer; aFont: FontRecord; previousFamily, previousFace, previousStyle: Str255; Begin UnlockHandle(aMenu); a := CountMItems(aMenu); For e := a Downto 1 Do DelMenuItem(aMenu, e); Case aContents Of familyMenu: Begin previousFamily := ''; e := 0; For a := 0 To Count Do Begin aFont := GetEntry(a); If aFont.PSFamily <> previousFamily Then Begin InsMenuItem(aMenu, aFont.PSFamily, e); e := e + 1; previousFamily := aFont.PSFamily; i := CountMItems(aMenu); End; End; End; faceMenu: Begin previousFace := ''; e := 0; For a := 0 To Count Do Begin aFont := GetEntry(a); If (aFont.PSFamily = aFamily) Then If (aFont.PSFace <> previousFace) Then Begin InsMenuItem(aMenu, aFont.PSFace, e); e := e + 1; previousFace := aFont.PSFace; i := CountMItems(aMenu); End; End; End; styleMenu: Begin previousStyle := ''; e := 0; For a := 0 To Count Do Begin aFont := GetEntry(a); If (aFont.PSFamily = aFamily) Then If (aFont.PSFace = aFace) Then If aFont.PSStyle <> previousStyle Then Begin InsMenuItem(aMenu, aFont.PSStyle, e); e := e + 1; previousStyle := aFont.PSStyle; i := CountMItems(aMenu); End Else If e > 0 Then a := Count; End; End; Otherwise Caution('Tried to fill a typeface-related menu with unknown items.'); End; LockHandle(aMenu); End; Procedure Typographer.Develop; Var aFond: Handle; aFondRec: FondRecord; aStyleMap: StyleMappingTable; aStyleList: Array[1..48] Of Str255; numFonds, currentFond, numFonts: Integer; aType: ResType; aName: Str255; aNum: Integer; tempFont: FontRecord; Procedure DoFond; Var minIndex, maxIndex: Integer; Procedure CountIndexes; Var e: Integer; Begin minIndex := 32767; maxIndex := 0; For e := 0 To 47 Do Begin If Ord(aStyleMap.StyleIndex[e]) > maxIndex Then maxIndex := Ord(aStyleMap.StyleIndex[e]); If Ord(aStyleMap.StyleIndex[e]) > 0 Then If Ord(aStyleMap.StyleIndex[e]) < minIndex Then minIndex := Ord(aStyleMap.StyleIndex[e]); End; End; Procedure GetStyles; Var a: Integer; aPtr: Ptr; aStr: Str255; Begin aPtr := Ptr(Longint(@aFond^^) + aFondRec.StyleMapOff + Longint(60)); For a := 1 To aStyleMap.NumStyles Do Begin BlockMove(aPtr, @aStyleList[a], Ord(Char(aPtr^)) + 1); aPtr := Ptr(Longint(aPtr) + Length(aStyleList[a]) + 1); End; If (Omit(aStyleList[1], 4, 255) = 'Itc') And (aStyleList[1][4] >= 'A') And (aStyleList[1][4] <= 'Z') Then aStyleList[1] := Omit(aStyleList[1], 1, 3); End; Procedure InterpretStyles; Var e, i: Integer; s, t: Str255; Begin For e := 2 To maxIndex Do Begin t := aStyleList[1]; For i := 1 To Length(aStyleList[e]) Do Begin s := aStyleList[Ord(aStyleList[e][i])]; If (s = 'ExtraBold') Or (s = 'Extra Bold') Then s := 'Extrabold'; t := Concat(t, s); End; aStyleList[e] := t; End; End; Function ReplaceTerm (aStr: Str255): Str255; Begin If aStr = 'Cond' Then ReplaceTerm := 'Condensed-' Else If aStr = 'Condensed' Then ReplaceTerm := 'Condensed-' Else If aStr = 'Light' Then ReplaceTerm := 'Light-' Else If aStr = 'Thin' Then ReplaceTerm := 'Thin-' Else If aStr = 'Medium' Then ReplaceTerm := 'Medium-' Else If aStr = 'Heavy' Then ReplaceTerm := 'Heavy-' Else If aStr = 'Heavyface' Then ReplaceTerm := 'Heavyface-' Else If aStr = 'Extrabold' Then ReplaceTerm := 'Extra Bold-' Else If aStr = 'Black' Then ReplaceTerm := 'Black-' Else If aStr = 'Book' Then ReplaceTerm := 'Book-' Else If aStr = 'Ultra' Then ReplaceTerm := 'Ultra-' Else If aStr = 'Obl' Then ReplaceTerm := 'Oblique' Else If aStr = 'Ita' Then ReplaceTerm := 'Italic' Else If aStr = 'Bol' Then ReplaceTerm := 'Bold' Else If aStr = 'Ital' Then ReplaceTerm := 'Italic' Else If aStr = 'Caslon' Then ReplaceTerm := 'Caslon-' Else If aStr = 'Giotto' Then ReplaceTerm := 'Giotto-' Else ReplaceTerm := aStr; End; Procedure RecognizeFace (Var aFace: Str255); Var a: Integer; Begin a := Pos('-', aFace); If a <> 0 Then Begin {Probably contains a valid style} Delete(aFace, a + 1, 255); End Else Begin If aFace = 'Open Face' Then aFace := 'Open Face' Else aFace := ''; End; End; Procedure ParseStyles; Var e, i, o, u: Integer; t, term: Str255; Begin For e := minIndex To maxIndex Do Begin u := Length(aStyleList[e]) - 1; t := ''; term := Concat('', aStyleList[e][1]); For o := 2 To u Do Begin If (aStyleList[e][o] >= 'A') And (aStyleList[e][o] <= 'Z') Then Begin t := Concat(t, Concat(ReplaceTerm(term), ' ')); term := ''; End; term := Concat(term, aStyleList[e][o]); End; t := Concat(t, ReplaceTerm(Concat(term, aStyleList[e][o]))); aStyleList[e] := t; End; End; Procedure DeriveNames (Var aFamily, aFace, aStyle: Str255); Var o: Integer; Begin o := Pos('-', aFace); If o = 0 Then Begin {Plain name} aFace := 'Regular'; aStyle := 'Regular'; End Else Begin {Really has a face name} Delete(aFamily, o, 255); If aFace[o + 1] = ' ' Then o := o + 1; Delete(aFace, 1, o); RecognizeFace(aFace); Delete(aStyle, 1, o); o := Length(aFace); If o > 0 Then o := o + 1; If aStyle[o + 1] = ' ' Then o := o + 1; Delete(aStyle, 1, o); aStyle := Strip('-', aStyle); If (aStyle = '') Or (aStyle = ' ') Then aStyle := 'Regular'; If (aFace = '') Or (aFace = ' ') Then aFace := 'Regular' Else aFace := Strip('-', aFace); End; End; Function PSStyleIndexToQDStyle (aByte: Byte): Style; Var aStyle: Style; Begin aStyle := []; If BTST(aByte, 0) Then aStyle := aStyle + [bold]; If BTST(aByte, 1) Then aStyle := aStyle + [italic]; If BTST(aByte, 2) Then aStyle := aStyle + [outline]; If BTST(aByte, 3) Then aStyle := aStyle + [shadow]; If BTST(aByte, 4) Then aStyle := aStyle + [condense]; If BTST(aByte, 5) Then aStyle := aStyle + [extend]; PSStyleIndexToQDStyle := aStyle; End; Procedure WriteStyles; Var e, i: Integer; aFamily, aFace, aStyle: Str255; Begin For e := minIndex To maxIndex Do For i := 0 To 47 Do If aStyleMap.StyleIndex[i] = e Then Begin With tempFont Do Begin aFamily := aStyleList[e]; aFace := aStyleList[e]; aStyle := aStyleList[e]; DeriveNames(aFamily, aFace, aStyle); PSFamily := aFamily; PSFace := aFace; PSStyle := aStyle; QDFont := aName; QDFace := aNum; QDStyle := PSStyleIndexToQDStyle(i); End; Insert(tempFont); numFonts := numFonts + 1; i := 47; End; End; Begin aFond := GetIndResource('FOND', currentFond); If Denied(aFond) Then {Caution('Could not get a FOND resource.')} Else Begin LockHandle(aFond); GetResInfo(aFond, aNum, aType, aName); BlockMove(Ptr(@aFond^^), @aFondRec, SizeOf(aFondRec)); If aFondRec.StyleMapOff > 0 Then Begin BlockMove(Ptr(Longint(@aFond^^) + aFondRec.StyleMapOff), @aStyleMap, SizeOf(StyleMappingTable)); CountIndexes; GetStyles; InterpretStyles; ParseStyles; WriteStyles; End Else With tempFont Do Begin PSFamily := aName; PSFace := 'Regular'; QDFont := aName; QDFace := aNum; PSStyle := 'Regular'; QDStyle := []; Insert(tempFont); PSStyle := 'Bold'; QDStyle := [bold]; Insert(tempFont); PSStyle := 'Bold Italic'; QDStyle := [bold] + [italic]; Insert(tempFont); PSStyle := 'Italic'; QDStyle := [italic]; Insert(tempFont); End; UnlockHandle(aFond); ReleaseResource(Handle(aFond)); End; End; Begin Expect(CountResources('FONT') + CountResources('NFNT') + CountResources('sfnt') + CountResources('FOND')); numFonds := CountResources('FOND'); numFonts := 0; For currentFond := 1 To numFonds Do DoFond; Sort; Unique; theTypographer.Expect(theTypographer.Count + 1); Fonds := numFonds; End; Procedure Typographer.Sort; Function GetKeyFromIndex (anIndex: Integer): Str255; Var aFont: FontRecord; Begin If (anIndex >= 0) And (anIndex <= Count) Then Begin aFont := GetEntry(anIndex); GetKeyFromIndex := Concat(Concat(aFont.PSFamily, aFont.PSFace), aFont.PSStyle); End Else GetKeyFromIndex := ''; End; Function GetKey (aFont: FontRecord): Str255; Begin GetKey := Concat(Concat(aFont.PSFamily, aFont.PSFace), aFont.PSStyle); End; Procedure QuickSort (l, r: Integer); Const QuickSortOverhead = Longint(SizeOf(FontRecord) * 2 + SizeOf(Integer) * 2); Var v, t: FontRecord; i, j: Integer; Begin If r > l Then Begin If StackSpace < QuickSortOverhead Then Danger('The typeface Typographer cannot be sorted.'); v := GetEntry(r); i := l - 1; j := r; Repeat Repeat i := i + 1 Until (GetKeyFromIndex(i) >= GetKey(v)); Repeat j := j - 1 Until (GetKeyFromIndex(j) <= GetKey(v)); t := GetEntry(i); SetEntry(i, GetEntry(j)); SetEntry(j, t); Until j <= i; SetEntry(j, GetEntry(i)); SetEntry(i, GetEntry(r)); SetEntry(r, t); QuickSort(l, i - 1); QuickSort(i + 1, r); End; End; Begin {QuickSort(0, Count);} End; Procedure Typographer.Unique; Var a, e: Integer; this, last: FontRecord; Begin e := 0; last := GetEntry(0); For a := 1 To Count Do Begin this := GetEntry(a); If (this.PSFamily = last.PSFamily) And (this.PSFace = last.PSFace) And (this.PSStyle = last.PSStyle) Then e := e + 1 Else SetEntry(a - e, this); last := this; End; Count := Count - e; End; Procedure Typographer.Harmony; Var a, e, i, o: Integer; this, next, temp: FontRecord; found, reported: Boolean; lastA, lastB: Str255; timer: Longint; Begin found := false; reported := false; lastA := ''; lastB := ''; a := Count - 1; For e := 0 To a Do Begin this := GetEntry(e); o := e + 1; For i := o To Count Do Begin next := GetEntry(i); If (next.QDFont <> this.QDFont) Then If (next.QDFace = this.QDFace) Then If (this.QDFont <> lastA) And (next.QDFont <> lastB) Then Begin If found And Not reported Then Begin Stop('Font resource number conflicts have been detected.'); Notice(Concat('The fonts ', Concat(Concat(Concat(lastA, ' and '), lastB), ' have the same font resource numbers.'))); reported := true; End; If found Then Notice(Concat('The fonts ', Concat(Concat(Concat(this.QDFont, ' and '), next.QDFont), ' have the same font resource numbers.'))); found := true; lastA := this.QDFont; lastB := next.QDFont; End; End; End; If found And Not reported Then Begin Stop('A font resource number conflict has been detected.'); Notice(Concat('The fonts ', Concat(Concat(Concat(lastA, ' and '), lastB), ' have the same font resource numbers.'))); End; End; Procedure Typographer.Destruct; Begin Dispose; End; - ------- Cut here Theus (orpheus@reed.edu) +++++++++++++++++++++++++++ From: ewylie@ocf.berkeley.edu (Elizabeth Wylie) Date: 12 Jun 1992 05:06:28 GMT Organization: U.C. Berkeley Open Computing Facility Thanks to all who responded. I was not able to find the adobe information on sumex-aim (has it been removed) but I enquired at adobe and they are sending me their TechNote #2 and a disk. Several people made the assumption that 'there must be a better way of finding out what you need to know'. I suppose I wasn't clear enough. I need to know whether 17 point Helvetica (for instance) will be drawn as a scaled bitmap or if ATM will take over and draw it as PostScript. The only clean way to do this is to ask ATM via it's backdoor routines. - -Elizabeth .   --------------------------- End of C.S.M.P. Digest **********************